#include "terra-ge/terra-ge.h"
#include "terra-ge/game/game.h"
#include "terra-ge/render/vobject_complex.h"
#include "terra-ge/render/light.h"

using namespace TerraGE;

ALLEGRO_FONT *font;

list<VObject *> vobjects;
list<Light *> lights;
Light *directional;

Camera *cam;

VObject_Complex *pilar;
VObject_Complex *robot;
VObject_Complex *teapot;
VObject_Complex *sphere;
int debug_mode;

ALLEGRO_BITMAP *b1;
ALLEGRO_BITMAP *b2;

void MainGame_Start(void *instance) {
    Game *gInstance = (Game *) instance;
    gInstance->Get_Log()->Write("Starting Game Scene.");

    Light *lg;
    lights.push_back(lg=new Light(0, 50, 10, 800, 1.2, 1, 0.8));

    directional = new Light(-1, -1, 1, 300, 1.3, 1.2, 1);
    directional->Normalize();
    directional->Set_Strength(1.0);
    directional->Set_Ambience(.5);

    gInstance->Get_Log()->Write("Lights created.");

    font = al_load_font("assets/font/GameFont.ttf", 16, 0);

    gInstance->Get_Log()->Write("Game Font loaded.");

    cam = new Camera();
    cam->Set_Map_Width(3000);
    cam->Set_Map_Height(4000);
    cam->Set_Map_Tall(2400);

    gInstance->Get_Log()->Write("Camera created");

    Bitmap_Manager *bm;
    bm = gInstance->Get_Bitmap_Manager();

    for (int x=0; x<3; x++) {
        for (int y=0; y<3; y++) {
            vobjects.push_back(new VObject_Complex(bm, cam, "tiles", x*1080, y*1080, 0, 1, true));
        }
    }

    pilar = new VObject_Complex(bm, cam, "square", 150, 150, 0, 1, true);
    vobjects.push_back(pilar);
/*
    pilar = new VObject_Complex(bm, cam, "house", 1350, 750, 0, 0.5, true);
    vobjects.push_back(pilar);

    pilar = new VObject_Complex(bm, cam, "sphere", 250, 950, 0, 1, true);
    vobjects.push_back(pilar);

    pilar = new VObject_Complex(bm, cam, "robot", 600, 1750, 0, 1, true);
    vobjects.push_back(pilar);

    pilar = new VObject_Complex(bm, cam, "pilar", 1300, 1850, 0, 1, true);
    vobjects.push_back(pilar);
*/
    pilar = new VObject_Complex(bm, cam, "light", 100, 800, 300, 1, false);
    pilar->Attach_Light(lg);
    vobjects.push_back(pilar);

    b1 = al_load_bitmap("b1.png");
    b2 = al_load_bitmap("b2.png");

    gInstance->Get_Log()->Write("Objects created");

    debug_mode=0;
}


void MainGame_Close(void *instance) {
    Game *gInstance = (Game *) instance;

}



void MainGame_Update(void *instance, float timestep) {
    Game *gInstance = (Game *) instance;
    Renderer *r=gInstance->Get_First_Renderer();

    if (KB_Input[ALLEGRO_KEY_ESCAPE]) gInstance->Set_Scene("");


    if (debug_mode&DEBUG_EDITOR) {
        float highest_z, tz;
        VObject_Complex *sel=NULL;
        VObject_Complex *vc=NULL;
        highest_z = -9999999;

        if (KB_TimePressed[ALLEGRO_KEY_MOUSE_LCLICK] < 5) {
            for (list<VObject *>::iterator it=vobjects.begin(); it!=vobjects.end(); it++) {
                if ((*it)->Get_Type() != VOBJECT_COMPLEX) continue;
                vc = (VObject_Complex *) *it;
                vc->Set_Hover(false);
                Vec2D pos, offset;
                offset = cam->Screen_To_Proj(vc->Get_CX()*vc->Get_Scale(), vc->Get_CY()*vc->Get_Scale());
                pos = cam->Proj_To_Screen((*it)->Get_X()-offset.x, (*it)->Get_Y()-offset.y, (*it)->Get_Z());
                pos.x -= cam->Get_X();
                pos.y -= cam->Get_Y();
                pos.x = r->XtoRX(pos.x);
                pos.y = r->YtoRY(pos.y);
                if ((mouse_x > pos.x) && (mouse_x < pos.x + r->XtoRX((*it)->Get_W()*vc->Get_Scale())) && (mouse_y > pos.y) && (mouse_y < pos.y+r->YtoRY((*it)->Get_H()*vc->Get_Scale()))) {
                    int pix_x, pix_y;
                    pix_x = r->RXtoX((mouse_x-pos.x) / vc->Get_Scale());
                    pix_y = r->RYtoY((mouse_y-pos.y) / vc->Get_Scale());
                    unsigned char r,g,b,a;
                    al_unmap_rgba(al_get_pixel(vc->Get_Actual_Bit(), pix_x, pix_y), &r, &g, &b, &a);
                    if (a < 2) continue;

                    sel = (VObject_Complex *) *it;
                }
            }
        }

        if (sel) sel->Set_Hover(true);
        if (KB_Input[ALLEGRO_KEY_MOUSE_MCLICK]) {
             for (list<VObject *>::iterator it=vobjects.begin(); it!=vobjects.end(); it++) {
                if ((*it)->Get_Type() != VOBJECT_COMPLEX) continue;
                vc = (VObject_Complex *) *it;
                vc->Deselect();
             }
            if (sel) sel->Select_Toggle();
        }

        if (KB_Active[ALLEGRO_KEY_MOUSE_LCLICK]) {
            for (list<VObject *>::iterator it=vobjects.begin(); it!=vobjects.end(); it++) {
                if ((*it)->Get_Type() != VOBJECT_COMPLEX) continue;
                VObject_Complex *vc;
                vc = (VObject_Complex *) (*it);
                vc->Set_Hover(false);
                if (!vc->Is_Selected()) continue;

                Vec2D pos = cam->Screen_To_Proj(r->RXtoX(mouse_x)+cam->Get_X(), r->RYtoY(mouse_y)+cam->Get_Y(), 0);
                vc->Set_X(pos.x);
                vc->Set_Y(pos.y);
            }
        }

        if (KB_Active[ALLEGRO_KEY_MOUSE_RCLICK]) {
            /*if (KB_Active[ALLEGRO_KEY_ALT]) {
                float tz;
                tz = cam->Get_Zoom();
                tz += -mick_y*.004*timestep;
                if (tz < 0.01) tz = 0.01;
                cam->Set_Zoom(tz);
            }*/
            for (list<VObject *>::iterator it=vobjects.begin(); it!=vobjects.end(); it++) {
                if ((*it)->Get_Type() != VOBJECT_COMPLEX) continue;
                VObject_Complex *vc;
                vc = (VObject_Complex *) (*it);
                vc->Set_Hover(false);
                if (!vc->Is_Selected()) continue;

                if (KB_Active[ALLEGRO_KEY_LCTRL]) {
                    float tz, t;
                    tz = vc->Get_Scale();
                    tz += -mick_y*.004*timestep;
                    if (tz < 0.01) tz = 0.01;
                    vc->Set_Scale(tz);
                }
                else {
                    float tz, t;
                    tz = vc->Get_Z();
                    tz += -mick_y*timestep;
                    if (tz < 0.01) tz = 0.01;
                    t = cam->Get_Map_Tall()-vc->Get_Tall();
                    if (tz >= t) tz = t;
                    vc->Set_Z(tz);
                }
            }
        }
    }



    for (list<VObject *>::iterator it=vobjects.begin(); it!=vobjects.end(); it++) (*it)->Update(timestep);
    for (list<Light *>::iterator it=lights.begin(); it!=lights.end(); it++) (*it)->Update(timestep);

    if (KB_Active[ALLEGRO_KEY_LEFT]) cam->Move_Target_X(-5*timestep);
    if (KB_Active[ALLEGRO_KEY_UP]) cam->Move_Target_Y(-5*timestep);
    if (KB_Active[ALLEGRO_KEY_RIGHT]) cam->Move_Target_X(5*timestep);
    if (KB_Active[ALLEGRO_KEY_DOWN]) cam->Move_Target_Y(5*timestep);

    if (KB_Input[ALLEGRO_KEY_L]) {
        Vec2D pos = cam->Screen_To_Proj(r->RXtoX(mouse_x)+cam->Get_X(), r->RYtoY(mouse_y)+cam->Get_Y(), 0);

        Light *lg;
        lights.push_back(lg=new Light(pos.x, pos.y, 300, 400, 1.2, 1, 0.8));

        pilar = new VObject_Complex(gInstance->Get_Bitmap_Manager(), cam, "light", pos.x, pos.y, 300, 1, false);
        pilar->Attach_Light(lg);
        vobjects.push_back(pilar);
    }


    int l1, l2, l3, l4, l5;
    l1 = debug_mode & DEBUG_LIGHTS;
    l2 = debug_mode & DEBUG_HEIGHT;
    l3 = debug_mode & DEBUG_NORMALS;
    l4 = debug_mode & DEBUG_NO_LIGHTING;
    l5 = debug_mode & DEBUG_EDITOR;
    if (KB_Input[ALLEGRO_KEY_F1]) l1 = (l1 ? 0 : DEBUG_LIGHTS);
    if (KB_Input[ALLEGRO_KEY_F2]) l2 = (l2 ? 0 : DEBUG_HEIGHT);
    if (KB_Input[ALLEGRO_KEY_F3]) l3 = (l3 ? 0 : DEBUG_NORMALS);
    if (KB_Input[ALLEGRO_KEY_F4]) l4 = (l4 ? 0 : DEBUG_NO_LIGHTING);
    if (KB_Input[ALLEGRO_KEY_F5]) l5 = (l5 ? 0 : DEBUG_EDITOR);

    debug_mode = l1 | l2 | l3 | l4 | l5;


    cam->Update(timestep);
}


void get_gl_size(int &width, int &height)
{
    int iv[4];
    glGetIntegerv(GL_VIEWPORT, iv);
    width = iv[2];
    height = iv[3];
}


void visualize_depth_buffer()
{
    int width, height;

    get_gl_size(width, height);

    float *data = new float[width * height];

    glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, data);
    glDrawPixels(width, height, GL_LUMINANCE, GL_FLOAT, data);

    delete [] data;
}

void MainGame_Draw(void *instance) {
    static float my_float=0;
    Game *gInstance = (Game *) instance;
    al_clear_to_color(al_map_rgb(100, 100, 100));

    my_float+= 0.01;

    gInstance->Get_First_Renderer()->Render(gInstance->Get_Log(), &vobjects, &lights, directional, cam, debug_mode);

    if (KB_Active[ALLEGRO_KEY_D]) visualize_depth_buffer();
}
